#include "stm32f30x.h"
#include "main.h"
#include <stdio.h>

#define I2C_RX_BUFF_LEN 256
#define I2C_TX_BUFF_LEN 256

uint8_t g_i2c_rx_buff[I2C_RX_BUFF_LEN];
uint8_t g_i2c_tx_buff[I2C_TX_BUFF_LEN];

static volatile uint32_t rx_idx = 0;
static volatile uint32_t tx_idx = 0;

#define I2C_RECV_DIR 0
#define I2C_TRAN_DIR 1

static uint8_t transfer_dir = I2C_RECV_DIR;


void i2c_buff_init()
{
    int i;
	for (i = 0; i < I2C_TX_BUFF_LEN; i++) {
		g_i2c_tx_buff[i] = i;
    }
}

void i2c1_gpio_deinit()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; // scl
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; // sda
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void i2c1_init()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	I2C_InitTypeDef I2C_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_I2CCLKConfig(RCC_I2C2CLK_HSI);
	I2C_Cmd(I2C1, DISABLE);
	i2c1_gpio_deinit();

    RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,ENABLE);
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,DISABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,DISABLE);
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	
	/* Disable the IRQ channel */
	NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
	
	/* Disable I2Cx EVT IRQn */
	NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;
	NVIC_Init(&NVIC_InitStructure);

	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB,ENABLE);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_4); // scl
 	GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_4); // sda
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL; //  kunkka
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; // scl 
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; // sda
	GPIO_Init(GPIOB, &GPIO_InitStructure);

    RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,ENABLE);
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,DISABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);

	/* Initialize I2C_InitStructure to their default values */
	I2C_InitStructure.I2C_Timing			  = I2C_TIMING;							   /* Initialize the I2C_Timing member */
	I2C_InitStructure.I2C_Mode				  = I2C_Mode_I2C;				   /* Initialize the I2C_Mode member */
	I2C_InitStructure.I2C_AnalogFilter		  = I2C_AnalogFilter_Enable;	   /* Initialize the I2C_AnalogFilter member */
	I2C_InitStructure.I2C_DigitalFilter 	  = 0x00;						   /* Initialize the I2C_DigitalFilter member */
	I2C_InitStructure.I2C_OwnAddress1		  = 0x60 << 1; //OWN_ADDRESS;							   /* Initialize the I2C_OwnAddress1 member */
	I2C_InitStructure.I2C_Ack				  = I2C_Ack_Enable; 			   /* Initialize the I2C_Ack member */
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;  /* Initialize the I2C_AcknowledgedAddress member */
	I2C_Init(I2C1, &I2C_InitStructure);
	I2C_StretchClockCmd(I2C1, DISABLE);

	/* Enable the IRQ channel */
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

	/* Configure NVIC for I2Cx EVT Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&NVIC_InitStructure);

	
    /* Configure NVIC for I2Cx ERR Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_Init(&NVIC_InitStructure);

	I2C_ITConfig(I2C1, I2C_CR1_ERRIE | I2C_CR1_NACKIE , ENABLE);
	I2C_ITConfig(I2C1, I2C_CR1_ADDRIE /*| I2C_CR1_TCIE */ | I2C_CR1_STOPIE | I2C_CR1_TXIE | I2C_CR1_RXIE , ENABLE);
}

void I2C1_EV_IRQHandler(void)
{
    volatile uint32_t isr_reg = I2C_ReadRegister(I2C1, I2C_Register_ISR);
	uint32_t I2CFlagStatus = isr_reg & 0x0000000FE;
	if (I2CFlagStatus & I2C_ISR_ADDR) {
        rx_idx = 0;
	    tx_idx = 0;
		transfer_dir = (isr_reg & I2C_ISR_DIR) ? I2C_TRAN_DIR : I2C_RECV_DIR;
		I2C_ClearFlag(I2C1, I2C_FLAG_ADDR);
		if (transfer_dir == I2C_TRAN_DIR) {
			I2C1->ISR = I2C_ISR_TXE;
			I2C_SendData(I2C1, g_i2c_tx_buff[tx_idx]);
			tx_idx++;
	    }
    }

    if (I2CFlagStatus & I2C_ISR_TXIS) {
		I2C_SendData(I2C1, g_i2c_tx_buff[tx_idx]);
		tx_idx = (tx_idx + 1) % I2C_TX_BUFF_LEN;
	}

	if (I2CFlagStatus & I2C_ISR_RXNE) {
		g_i2c_rx_buff[rx_idx] = I2C_ReceiveData(I2C1);
		rx_idx = (rx_idx + 1) % I2C_RX_BUFF_LEN;
	}
	if (I2CFlagStatus & I2C_ISR_NACKF) {
		I2C_ClearFlag(I2C1, I2C_ICR_NACKCF);
		if (transfer_dir == I2C_RECV_DIR) {
			//printf("i2c rx nak ok rx_idx = %ld\n", rx_idx);
	    } else {
	        //printf("i2c tx nak ok tx_idx = %ld\n", tx_idx);
	    }
	}
    if (I2CFlagStatus & I2C_ISR_STOPF) {
		I2C_ClearFlag(I2C1, I2C_ICR_STOPCF);
		if (transfer_dir == I2C_RECV_DIR) {
			g_i2c_recv_len = rx_idx;
			g_i2c_recv_packet_ready = 1;
			//printf("i2c rx2 ok rx_idx = %ld\n", rx_idx);
	    } else {
	        //printf("i2c tx2 ok tx_idx = %ld\n", tx_idx);
	    }
	}
}

void I2C1_ER_IRQHandler(void)
{
	volatile uint32_t state_err = I2C_ReadRegister(I2C1, I2C_Register_ISR);
	state_err &= 0x00000700;
	printf("i2c isr error: %lx\n", state_err);
	
	if (state_err & I2C_FLAG_BERR) {
		I2C_ClearFlag(I2C1, I2C_FLAG_BERR);
	}
    if (state_err & I2C_FLAG_ARLO) {
		I2C_ClearFlag(I2C1, I2C_FLAG_ARLO);
	}
	if (state_err & I2C_FLAG_OVR) {
		I2C_ClearFlag(I2C1, I2C_FLAG_OVR);
	}
	i2c1_init();
}

